# -*- coding: cp1252 -*-
import wx, random, dircache
import wx.aui, wx.html, wx.grid
from wx.lib.buttons import GenBitmapTextButton
import wx.stc as stc
from lxml import etree
from lxml.etree import XML, XMLSyntaxError
from StringIO import StringIO
import os, os.path, sys, codecs
import time
import datetime
import string


MYSTRING ="""<canvas width="240">
  <text x="5" y="5" >try dragging divider</text>

  <view id="divider" x="110" y="30"
        width="10" height="200" bgcolor="#"
        onmousedown="dragging.apply()"
        onmouseup="dragging.remove()">
    <state name="dragging">
      <attribute name="x"
                 value="${parent.getMouse('x')}"/>
    </state>
  </view>

  <!-- constrain width to x of 'divider' -->
  <view name="left" bgcolor="#" y="30"
        width="${divider.x}" height="200" >
    <text x="5" y="5" >Left Panel</text>
    <method name="hello">
        [CDATA[
        a = a + 1
        ]]
    </method>
  </view>

  <!-- constrain to properties of 'divider' -->
  <view name="right" bgcolor="#CAD0EC" y="30"
        x="${divider.x+divider.width}"
        width="${parent.width-this.x}" height="200" >
    <text x="5" y="5" >Right Panel</text>
  </view>
</canvas>

"""
TEXT_ABOUT = '''
<html>
<body>
<img src="icons/SplashScreen.png"/>
</body>
</html>
'''


if wx.Platform == '__WXMSW__':
    OS_BASEPATH = 'C:\\Program Files\\OpenLaszlo Server 4.0.5'
    faces = { 'times': 'Times New Roman',
              'mono' : 'Courier New',
              'helv' : 'Arial',
              'other': 'Comic Sans MS',
              'size' : 12,
              'size2': 10,
             }
elif wx.Platform == '__WXMAC__':
    OS_BASEPATH = '<unknown>'
    faces = { 'times': 'Times New Roman',
              'mono' : 'Courier New',
              'helv' : 'Arial',
              'other': 'Comic Sans MS',
              'size' : 12,
              'size2': 10,
             }
else:
    OS_BASEPATH = '\\usr\\bin\\'
    faces = { 'times': 'Times',
              'mono' : 'Courier',
              'helv' : 'Helvetica',
              'other': 'new century schoolbook',
              'size' : 12,
              'size2': 10,
             }


## Standard Text
TEXT_DEFAULT_NEWFILE = "* new"
##--------- ICONS ----------
## FILE MENU
ICON_MENU_FILE_NEW1 = 'icons/menu/fileMenu/filenew.png'
ICON_MENU_FILE_NEW2 = 'icons/menu/fileMenu/filenew.png'
ICON_MENU_FILE_NEW3 = 'icons/menu/fileMenu/filenew.png'
ICON_MENU_FILE_NEW4 = 'icons/menu/fileMenu/filenew.png'
ICON_MENU_FILE_OPEN = 'icons/menu/fileMenu/fileopen.png'
ICON_MENU_FILE_SAVE = 'icons/menu/fileMenu/filesave.png'
ICON_MENU_FILE_SAVEAS = 'icons/menu/fileMenu/filesaveas.png'
ICON_MENU_FILE_CLOSE = 'icons/menu/fileMenu/fileclose.png'
ICON_MENU_FILE_CLOSEALL = 'icons/menu/fileMenu/fileclose.png'
ICON_MENU_FILE_PRINT = 'icons/menu/fileMenu/print.png'
ICON_MENU_FILE_EXIT = 'icons/menu/fileMenu/exit.png'
## EDIT MENU
ICON_MENU_EDIT_CUT = 'icons/menu/editMenu/editcut.png'
ICON_MENU_EDIT_COPY = 'icons/menu/editMenu/editcopy.png'
ICON_MENU_EDIT_PASTE = 'icons/menu/editMenu/editpaste.png'
ICON_MENU_EDIT_DELETE = 'icons/menu/editMenu/editdelete.png'
ICON_MENU_EDIT_UNDO = 'icons/menu/editMenu/undo.png'
ICON_MENU_EDIT_REDO = 'icons/menu/editMenu/redo.png'
## FORMAT MENU
ICON_MENU_FORMAT_PRETTYPRINT = 'icons/menu/formatMenu/prettyPrint.png'
ICON_MENU_FORMAT_CHECKSYNTAX = 'icons/menu/formatMenu/checksyntax.png'
## HELP MENU
ICON_MENU_HELP_ABOUT = 'icons/menu/helpMenu/about.png'
ICON_MENU_HELP_PREFERENCES = 'icons/menu/helpMenu/preferences.png'
## STATUSBAR
ICON_STATUSBAR_SYNTAXOK = 'icons/statusbar/syntaxok.png'
## TOOLBAR
ICON_TOOLBAR_FILE_NEW = 'icons/toolbar/filenew.png'
ICON_TOOLBAR_FILE_OPEN = 'icons/toolbar/fileopen.png'
ICON_TOOLBAR_FILE_SAVE = 'icons/toolbar/filesave.png'
ICON_TOOLBAR_FILE_SAVEAS = 'icons/toolbar/filesaveas.png'
ICON_TOOLBAR_FILE_PRINT = 'icons/toolbar/fileprint.png'
ICON_TOOLBAR_PRETTYPRINT = 'icons/toolbar/prettyPrint.png'
ICON_TOOLBAR_UNDO = 'icons/toolbar/undo.png'
ICON_TOOLBAR_REDO = 'icons/toolbar/redo.png'
ICON_TOOLBAR_CHECKSYNTAX = 'icons/toolbar/checksyntax.png'
## SPLASH_SCREEN
ICON_SPLASH_SCREEN = 'icons/SplashScreen.png'
## OUTPUT PANEL
ICON_REDLED =    'icons/outputPanel/redled.png'
ICON_GREENLED =  'icons/outputPanel/greenled.png'
ICON_YELLOWLED = 'icons/outputPanel/yellowled.png'

##--------- EVENT ID's ----------
## File Menu Event ID's
ID_MENU_FILE_NEW1 = 101
ID_MENU_FILE_NEW2 = 102
ID_MENU_FILE_NEW3 = 103
ID_MENU_FILE_NEW4 = 104
ID_MENU_FILE_OPEN = 105
ID_MENU_FILE_SAVE = 106
ID_MENU_FILE_SAVEAS = 107
ID_MENU_FILE_CLOSE = 108
ID_MENU_FILE_CLOSEALL = 109
ID_MENU_FILE_PRINT = 110
ID_MENU_FILE_EXIT = 111
## Edit Menu Event ID's
ID_MENU_EDIT_CUT = 120
ID_MENU_EDIT_COPY = 121
ID_MENU_EDIT_PASTE = 122
ID_MENU_EDIT_DELETE = 123
ID_MENU_EDIT_UNDO = 124
ID_MENU_EDIT_REDO = 125
## Format Menu Event ID's
ID_MENU_FORMAT_PRETTYPRINT = 140
ID_MENU_FORMAT_EOL = 141
ID_MENU_FORMAT_CHECKSYNTAX = 142
## Help Menu Event ID's
ID_MENU_HELP_ABOUT = 150
ID_MENU_HELP_PREFERENCES = 151

## Toolbar Event ID's
ID_TOOLBAR_FILE_NEW = 200
ID_TOOLBAR_FILE_OPEN = 201
ID_TOOLBAR_FILE_SAVE = 202
ID_TOOLBAR_UNDO = 203
ID_TOOLBAR_REDO = 204
ID_TOOLBAR_PRETTYPRINT = 205
ID_TOOLBAR_CHECKSYNTAX = 206


class MyStatusBar(wx.StatusBar):
    def __init__(self, parent):
        wx.StatusBar.__init__(self, parent)
        self.SetFieldsCount(2)
        self.SetStatusText('Welcome to OpenPavilion', 1)
        self.SetStatusWidths([20, -1])
        self.icon = wx.StaticBitmap(self, -1, wx.Bitmap(ICON_STATUSBAR_SYNTAXOK))
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.PlaceIcon()
        self.SetBackgroundColour(wx.Colour(0,0,255))        

    def PlaceIcon(self):
        rect = self.GetFieldRect(0)
        self.icon.SetPosition((rect.x+3, rect.y+3))

    def OnSize(self, event):
        self.PlaceIcon()

class MyMenuBar(wx.MenuBar):
    def __init__(self, parent):
        wx.MenuBar.__init__(self)
        self._appendFileMenu()
        self._appendEditMenu()
        self._appendFormatMenu()
        self._appendHelpMenu()
        self._bindEvents(parent)

        
    def _appendFileMenu(self):
        fileMenu = wx.Menu()
        
        submenuFileNew = wx.Menu()
        self.appendMenuItem(submenuFileNew, ID_MENU_FILE_NEW1,      'Canvas',      'OpenLaszlo Canvas',         ICON_MENU_FILE_NEW1)
        self.appendMenuItem(submenuFileNew, ID_MENU_FILE_NEW2,      'Library',     'OpenLaszlo Library',   ICON_MENU_FILE_NEW2)
        self.appendMenuItem(submenuFileNew, ID_MENU_FILE_NEW3,      'page3',       'new Page3',         ICON_MENU_FILE_NEW3)
        self.appendMenuItem(submenuFileNew, ID_MENU_FILE_NEW4,      'lzx example',     'lzx example file',         ICON_MENU_FILE_NEW4)
        fileMenu.AppendMenu(wx.NewId(),"New",submenuFileNew)
        fileMenu.AppendSeparator()
        self.appendMenuItem(fileMenu, ID_MENU_FILE_OPEN,           'open',         'create new file',     ICON_MENU_FILE_OPEN)
        fileMenu.AppendSeparator()
        self.appendMenuItem(fileMenu, ID_MENU_FILE_SAVE,           'save',         'save file',           ICON_MENU_FILE_SAVE)
        self.appendMenuItem(fileMenu, ID_MENU_FILE_SAVEAS,         'save as ...',  'save files as ...',   ICON_MENU_FILE_SAVEAS)
        fileMenu.AppendSeparator()
        self.appendMenuItem(fileMenu, ID_MENU_FILE_CLOSE,          'close',        'close file',          ICON_MENU_FILE_CLOSE)
        self.appendMenuItem(fileMenu, ID_MENU_FILE_CLOSEALL,       'close all',    'close file',          ICON_MENU_FILE_CLOSEALL)
        fileMenu.AppendSeparator()
        self.appendMenuItem(fileMenu, ID_MENU_FILE_PRINT,          'print',        'print file',          ICON_MENU_FILE_PRINT)
        fileMenu.AppendSeparator()
        self.appendMenuItem(fileMenu, ID_MENU_FILE_EXIT,           'exit',         'exit application',    ICON_MENU_FILE_EXIT)
        self.Append(fileMenu, '&File')   
        
    def _appendEditMenu(self):
        editMenu = wx.Menu()
        self.appendMenuItem(editMenu, ID_MENU_EDIT_UNDO,     'undo',         'undo',             ICON_MENU_EDIT_UNDO)
        self.appendMenuItem(editMenu, ID_MENU_EDIT_REDO,     'redo',         'redo',             ICON_MENU_EDIT_REDO)
        editMenu.AppendSeparator()
        self.appendMenuItem(editMenu, ID_MENU_EDIT_CUT,      'cut',          'cut selected',     ICON_MENU_EDIT_CUT)
        self.appendMenuItem(editMenu, ID_MENU_EDIT_COPY,     'copy',         'copy selected',    ICON_MENU_EDIT_COPY)
        self.appendMenuItem(editMenu, ID_MENU_EDIT_PASTE,    'past',         'paste',            ICON_MENU_EDIT_PASTE)
        editMenu.AppendSeparator()
        self.appendMenuItem(editMenu, ID_MENU_EDIT_DELETE,   'delete',       'delete',           ICON_MENU_EDIT_DELETE)
        self.Append(editMenu, '&Edit')
    
    def _appendFormatMenu(self):
        formatMenu = wx.Menu()
        self.appendMenuItem(formatMenu, ID_MENU_FORMAT_PRETTYPRINT,  'pretty print',   'pretty print',   ICON_MENU_FORMAT_PRETTYPRINT)
        formatMenu.AppendSeparator()
        formatMenu.AppendCheckItem(ID_MENU_FORMAT_EOL, "Show LF, CR and EOL")
        formatMenu.AppendSeparator()
        self.appendMenuItem(formatMenu, ID_MENU_FORMAT_CHECKSYNTAX,  'syntax check',   'validate file',   ICON_MENU_FORMAT_CHECKSYNTAX)
        self.Append(formatMenu, '&Format')
    
    def _appendHelpMenu(self):
        helpMenu = wx.Menu()
        self.appendMenuItem(helpMenu, ID_MENU_HELP_PREFERENCES,  'Preferences',   'Preferences',   ICON_MENU_HELP_PREFERENCES)
        self.appendMenuItem(helpMenu, ID_MENU_HELP_ABOUT,  'About',   'About',   ICON_MENU_HELP_ABOUT)
        self.Append(helpMenu, '&Help')

    def appendMenuItem(self, menu, id, label, tooltip, image):
        menuItem = wx.MenuItem(menu, id, label, tooltip)
        menuItem.SetBitmap(wx.Image(image, wx.BITMAP_TYPE_PNG).ConvertToBitmap())
        menu.AppendItem(menuItem)
        return menuItem
        
    def _bindEvents(self, parent):
        parent.SetMenuBar(self)
        parent.Centre()
#        parent.Bind(wx.EVT_MENU, parent.OnAppendPage1, id=ID_MENU_FILE_NEW1)
#        parent.Bind(wx.EVT_MENU, parent.OnAppendPage2, id=ID_MENU_FILE_NEW2)
#        parent.Bind(wx.EVT_MENU, parent.OnAppendPage3, id=ID_MENU_FILE_NEW3)
        parent.Bind(wx.EVT_MENU, parent.OnNewPage,         id=ID_MENU_FILE_NEW4)
        parent.Bind(wx.EVT_MENU, parent.OnNewPage,         id=ID_TOOLBAR_FILE_NEW)
        parent.Bind(wx.EVT_MENU, parent.OnPrettyPrint,     id=ID_MENU_FORMAT_PRETTYPRINT)
        parent.Bind(wx.EVT_MENU, parent.OnPrettyPrint,     id=ID_TOOLBAR_PRETTYPRINT)
        parent.Bind(wx.EVT_MENU, parent.OnUndo,            id=ID_TOOLBAR_UNDO)
        parent.Bind(wx.EVT_MENU, parent.OnRedo,            id=ID_TOOLBAR_REDO)
        parent.Bind(wx.EVT_MENU, parent.OnUndo,            id=ID_TOOLBAR_UNDO)
        parent.Bind(wx.EVT_MENU, parent.OnRedo,            id=ID_TOOLBAR_REDO)
        parent.Bind(wx.EVT_MENU, parent.OnCheckSyntax,     id=ID_TOOLBAR_CHECKSYNTAX)       
        parent.Bind(wx.EVT_MENU, parent.OnToggleEOL,       id=ID_MENU_FORMAT_EOL)  
        parent.Bind(wx.EVT_MENU, parent.OnCheckSyntax,     id=ID_MENU_FORMAT_CHECKSYNTAX)
        parent.Bind(wx.EVT_MENU, parent.OnFileOpen,        id=ID_MENU_FILE_OPEN)
        parent.Bind(wx.EVT_MENU, parent.OnFileOpen,        id=ID_TOOLBAR_FILE_OPEN)
        parent.Bind(wx.EVT_MENU, parent.OnFileSave,        id=ID_MENU_FILE_SAVE)
        parent.Bind(wx.EVT_MENU, parent.OnFileSave,        id=ID_TOOLBAR_FILE_SAVE)
        parent.Bind(wx.EVT_MENU, parent.OnAbout,           id=ID_MENU_HELP_ABOUT)
        parent.Bind(wx.EVT_MENU, parent.OnPreferences,     id=ID_MENU_HELP_PREFERENCES)
        

class MyNotebookPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)
        self.parent = parent
        self.notebook = wx.aui.AuiNotebook(self)
        sizer = wx.BoxSizer()
        sizer.Add(self.notebook, 1, wx.EXPAND)
        self.SetSizer(sizer)        
    def addNewPage(self, text=MYSTRING, label=TEXT_DEFAULT_NEWFILE):
        xml_panel = MyXMLPanel(self.notebook)
        self.notebook.AddPage(xml_panel, label)
        xml_panel.styledTextEditor.SetText(text)
        xml_panel.styledTextEditor.EmptyUndoBuffer()
        self.notebook.GetPage(self.notebook.GetPageCount()-1).SetFocus()
    def savePage(self):
        filename= wx.SaveFileSelector("load file", "new.lzx", "*.lzx", parent=self)
        if filename != u"":
            f = open(filename, "w")
            f.write(self.getCurrentSTC().GetText())
            f.close()
    def getCurrentPanel(self):
        return self.notebook.GetPage(self.notebook.GetSelection())
    def getCurrentSTC(self):
        return self.getCurrentPanel().styledTextEditor
    def doPrettyPrint(self):
        try:
            self.getCurrentSTC().DoPrettyPrint()
            self._informUser("done pretty print")
        except:
            self._alarmUser("pretty print: function not available")
    def doUndo(self):
        try:
            self.getCurrentSTC().Undo()
            self._informUser("done undo")
        except:
            self._warnUser("undo: function not available")
    def doRedo(self):
        try:
            self.getCurrentSTC().Redo()
            self._informUser("done redo")
        except:
            self._warnUser("redo: function not available")
    def toggleEOL(self):
        try:
            self.getCurrentSTC().SetViewEOL(not self.getCurrentSTC().GetViewEOL())
            self.getCurrentSTC().SetViewWhiteSpace(not self.getCurrentSTC().GetViewWhiteSpace())
            self._informUser("presentation changed")
        except:
            self._warnUser("change presentation: function not available")
            
    def checkSyntax(self):
        try:
            self.getCurrentSTC().CheckSyntax()
            self._informUser("file is valid")
        except:
            self._alarmUser("Syntax check: file is no valid XML !!")
    
    def _informUser(self, message):
        myLaszloPartyFrame.informUser(message)

    def _warnUser(self, message):
        myLaszloPartyFrame.warnUser(message)
                
    def _alarmUser(self, message):
        myLaszloPartyFrame.alarmUser(message)

class MyToolBar(wx.ToolBar):
    def __init__(self, parent):
        wx.ToolBar.__init__(self, parent, -1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TB_3DBUTTONS | wx.TB_NODIVIDER)
        self.SetToolBitmapSize(wx.Size(22,22))
        self.bmp1 = wx.Bitmap(ICON_TOOLBAR_FILE_NEW)
        self.bmp2 = wx.Bitmap(ICON_TOOLBAR_FILE_OPEN)
        self.bmp3 = wx.Bitmap(ICON_TOOLBAR_FILE_SAVE)
        self.bmp4 = wx.Bitmap(ICON_TOOLBAR_PRETTYPRINT)
        self.bmp5 = wx.Bitmap(ICON_TOOLBAR_UNDO)  
        self.bmp6 = wx.Bitmap(ICON_TOOLBAR_REDO)
        self.bmp7 = wx.Bitmap(ICON_TOOLBAR_CHECKSYNTAX)             
        self.AddSimpleTool(ID_TOOLBAR_FILE_NEW,      self.bmp1,    shortHelpString="new")
        self.AddSimpleTool(ID_TOOLBAR_FILE_OPEN,     self.bmp2,    shortHelpString="open")
        self.AddSimpleTool(ID_TOOLBAR_FILE_SAVE,     self.bmp3,    shortHelpString="save")
        self.AddSimpleTool(ID_TOOLBAR_PRETTYPRINT,   self.bmp4,    shortHelpString="pretty print")
        self.AddSimpleTool(ID_TOOLBAR_UNDO,          self.bmp5,    shortHelpString="undo")
        self.AddSimpleTool(ID_TOOLBAR_REDO,          self.bmp6,    shortHelpString="redo")
        self.AddSimpleTool(ID_TOOLBAR_CHECKSYNTAX,   self.bmp7,    shortHelpString="check syntax")
        self.Realize()

class MyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1,size = (200, 200))
        self.button1 = wx.TextCtrl(self, -1, ' ', wx.DefaultPosition, wx.Size(800,150), wx.NO_BORDER | wx.TE_MULTILINE)
        sizer = wx.BoxSizer()
        sizer.Add(self.button1)
        self.SetSizer(sizer)

class MyXMLEditor(stc.StyledTextCtrl):
    def __init__(self, parent, ID,
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=0):
        stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
        self.parent = parent
        self._codeFolding = True
        self.setupEventHandling()
        self.setupHandling()
        self.colorize()

    def setupHandling(self):
        xmlKeywords = (
        "canvas window view button edittext text form calendar dataset datapath"
        )

        self.SetLexer(stc.STC_LEX_XML)
        self.SetKeyWords(stc.STC_LEX_XML, xmlKeywords)
        self.SetProperty("fold","1")
        self.SetProperty("fold.html","1")
        self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
        self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
        self.SetMarginSensitive(2, True)
        self.SetMarginWidth(2, 12)
        self._setCodeFolding()
        #self.SetViewEOL(True)
        #self.SetViewWhiteSpace(True)        

    def _setCodeFolding(self):
        """Sets the visibility of the code folding margin."""
        if not self._codeFolding:
            self.SetMarginSensitive(2, False)
            self.SetMarginWidth(2, 0)
        else:
            # Setup a margin to hold fold markers
            self.SetProperty("fold", "1")
            self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
            self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
            self.SetMarginSensitive(2, True)
            self.SetMarginWidth(2, 12)

            # Like a flattened tree control using square headers
            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080")
            self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080")
            self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080")
            self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080")
            self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
            self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
            self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080")



    def setupEventHandling(self):
        self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
        self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)

    def colorize(self):
        # Global default styles for all languages
        self.StyleClearAll()  # Reset all to be like the default
        self.SetCaretWidth(3)
        self.SetIndent(4)

        # Global default styles for all languages
        self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,  "back:#C0C0C0,face:%(mono)s,size:%(size2)d" % faces)
        self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "fore:#FF0000,face:%(mono)s" % faces)
        self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,  "fore:#0044FF,face:%(mono)s,back:#AAFF88,bold")
        self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,    "fore:#FFFF00,face:%(mono)s,back:#FF0000,bold")
        self.StyleSetSpec(stc.STC_STYLE_LASTPREDEFINED, "fore:#FF0000,face:%(mono)s" % faces)
        
        # XML styles
        self.StyleSetSpec(stc.STC_H_DEFAULT, "fore:#000000,face:%(mono)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_COMMENT, "fore:#BBBBBB,face:%(mono)s,size:%(size2)d, italic" % faces)
        self.StyleSetSpec(stc.STC_H_NUMBER, "fore:#007F7F,face:%(mono)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_SINGLESTRING, "fore:#00AA00,face:%(mono)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_DOUBLESTRING, "fore:#00AA00,face:%(mono)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_XMLSTART, "fore:#880088,face:%(helv)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_XMLEND, "fore:#880088,face:%(helv)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_TAG, "fore:#0044FF, face:%(helv)s,size:%(size)d, bold" % faces)
        self.StyleSetSpec(stc.STC_H_TAGEND, "fore:#0044FF,face:%(helv)s,size:%(size)d, bold" % faces)
        self.StyleSetSpec(stc.STC_H_ATTRIBUTE, "fore:#AA00AA, face:%(mono)s,size:%(size)d" % faces)
        self.StyleSetSpec(stc.STC_H_CDATA, "fore:#FF0000,face:%(mono)s,size:%(size2)d" % faces)

        self.SetCaretForeground("BLACK")

    def OnKeyPressed(self, event):
        if self.CallTipActive():
            self.CallTipCancel()
        key = event.GetKeyCode()

        if key == 32 and event.ControlDown():
            pos = self.GetCurrentPos()

            # Tips
            if event.ShiftDown():
                self.CallTipSetBackground("yellow")
                self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
                                 'show some suff, maybe parameters..\n\n'
                                 'fubar(param1, param2)')
            # Code completion
            else:
                kw = myLaszloPartyFrame.keywords.getLZXKeywordList()
                for a in myLaszloPartyFrame.keywords.getClassList():
                    kw.append(a)
                kw.sort()  # Python sorts are case sensitive
                self.AutoCompSetIgnoreCase(False)  # so this needs to match
                self.AutoCompShow(0, " ".join(kw))
        else:
            event.Skip()

    def OnUpdateUI(self, evt):
        # check for matching braces
        braceAtCaret = -1
        braceOpposite = -1
        charBefore = None
        caretPos = self.GetCurrentPos()

        if caretPos > 0:
            charBefore = self.GetCharAt(caretPos - 1)
            styleBefore = self.GetStyleAt(caretPos - 1)

        # check before
        if charBefore and chr(charBefore) in "<>" and styleBefore == stc.STC_H_TAG:
            braceAtCaret = caretPos - 1

        # check after
        if braceAtCaret < 0:
            charAfter = self.GetCharAt(caretPos)
            styleAfter = self.GetStyleAt(caretPos)

            if charAfter and chr(charAfter) in "<>" and styleAfter == stc.STC_H_TAG:
                braceAtCaret = caretPos

        if braceAtCaret >= 0:
            braceOpposite = self.BraceMatch(braceAtCaret)

        if braceAtCaret != -1  and braceOpposite == -1:
            self.BraceBadLight(braceAtCaret)
        else:
            self.BraceHighlight(braceAtCaret, braceOpposite)
            #pt = self.PointFromPosition(braceOpposite)
            #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
            #print pt
            #self.Refresh(False)


    def OnMarginClick(self, evt):
        # fold and unfold as needed
        if evt.GetMargin() == 2:
            if evt.GetShift() and evt.GetControl():
                self.FoldAll()
            else:
                lineClicked = self.LineFromPosition(evt.GetPosition())

                if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
                    if evt.GetShift():
                        self.SetFoldExpanded(lineClicked, True)
                        self.Expand(lineClicked, True, True, 1)
                    elif evt.GetControl():
                        if self.GetFoldExpanded(lineClicked):
                            self.SetFoldExpanded(lineClicked, False)
                            self.Expand(lineClicked, False, True, 0)
                        else:
                            self.SetFoldExpanded(lineClicked, True)
                            self.Expand(lineClicked, True, True, 100)
                    else:
                        self.ToggleFold(lineClicked)
    def DoPrettyPrint(self):
        doc = etree.parse(StringIO(self.GetText()))
        self.indentXML(doc.getroot())
        self.SetText(etree.tostring(doc))
    
    def indentXML(self, elem, level=0):
        i = "\n" + level*"  "
        if len(elem):
            if not elem.text or not elem.text.strip():
                elem.text = i + "  "
            for e in elem:
                self.indentXML(e, level+1)
                if not e.tail or not e.tail.strip():
                    e.tail = i + "  "
            if not e.tail or not e.tail.strip():
                e.tail = i
        else:
            if level and (not elem.tail or not elem.tail.strip()):
                elem.tail = i
    
    def CheckSyntax(self):
        doc = etree.parse(StringIO(self.GetText()))


class MyXMLPanel(wx.Panel):
    def __init__(self, parent, id=-1):
        wx.Panel.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE)
        self.parent = parent
        self.styledTextEditor = MyXMLEditor(self, -1, size=(700, 500))
        self.sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.sizer.Add(self.styledTextEditor, 1, wx.EXPAND)
        self.SetSizer(self.sizer)
        self.SetAutoLayout(True)
        self.styledTextEditor.EmptyUndoBuffer()
        self.styledTextEditor.Colourise(0, -1)
        self.styledTextEditor.SetMarginType(1, stc.STC_MARGIN_NUMBER)
        self.styledTextEditor.SetMarginWidth(1, 25)
    


class MyAUIManager(wx.aui.AuiManager):
    def __init__(self, parent):
        wx.aui.AuiManager.__init__(self, parent)
        self.AddPane(parent.projectSelector , wx.LEFT, 'Files')
        self.AddPane(parent.notebookPanel, wx.CENTER, 'Laszlo Editor')
        self.AddPane(parent.outputPanel, wx.BOTTOM, 'Output')
        self.AddPane(parent.toolbar, wx.aui.AuiPaneInfo().Name("tbvert").Caption("Sample Vertical Toolbar").ToolbarPane().Top().Gripper(False).TopDockable(False).BottomDockable(False))
        self.Update()        

class MyOutputList(wx.ListCtrl):
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, size=(1000,200), style=wx.LC_REPORT)
        il = wx.ImageList(14,14, True)
        bmp1 = wx.Image(ICON_GREENLED, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
        bmp2 = wx.Image(ICON_YELLOWLED, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
        bmp3 = wx.Image(ICON_REDLED, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
        il.Add(bmp1)
        il.Add(bmp2)
        il.Add(bmp3)
        self.AssignImageList(il, wx.IMAGE_LIST_SMALL)
        self.InsertColumn(0,"Output")
        self.SetColumnWidth(0,1000)
    def alarmIcon(self):
        return 2
    def warningIcon(self):
        return 1
    def normalIcon(self):
        return 0

class AboutDialog(wx.Dialog):
    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, -1, 'About LaszloParty',
        size=(440, 380) )
        html = wx.html.HtmlWindow(self)
        html.SetPage(TEXT_ABOUT)
        button = wx.Button(self, wx.ID_OK, "close")
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(html, 1, wx.ALIGN_CENTER|wx.EXPAND|wx.ALL, 5)
        sizer.Add(button, 0, wx.ALIGN_CENTER|wx.ALL, 5)
        self.SetSizer(sizer)
        self.Layout()    
 
class PreferenceData:
    def __init__(self):
        self.cfg = wx.FileConfig('LaszoPartyConfig')
        if self.cfg.Exists('APP_WIDTH'):
            self.APP_WIDTH = self.cfg.ReadInt('APP_WIDTH')
            self.APP_HEIGHT = self.cfg.ReadInt('APP_HEIGHT')
            self.APP_X = self.cfg.ReadInt('APP_X')
            self.APP_Y = self.cfg.ReadInt('APP_Y')
            self.LZX_LPS_TOOLS_BASEPATH = self.cfg.Read("LZX_LPS_TOOLS_BASEPATH")
            self.LZX_LPS_COMPONENTS_BASEPATH = self.cfg.Read("LZX_LPS_COMPONENTS_BASEPATH")
        else:
            self.APP_HEIGHT = 1024
            self.APP_WIDTH = 1280
            self.APP_X = 0
            self.APP_Y = 0
            self.LZX_LPS_TOOLS_BASEPATH = OS_BASEPATH+'\\Server\\lps-4.0.5\\tools\\'
            self.LZX_LPS_COMPONENTS_BASEPATH = OS_BASEPATH+'\\Server\\lps-4.0.5\\lps\\components\\'

        self.LZX_LPS_TOOLS_GRAMMARFILE = 'lzx.rng'
        self.LZX_LPS_TOOLS_XMLSCHEMA = 'lzx.xsd'
        self.LZX_LPS_COMPONENTS_BASEFILE = 'library.lzx'            
    def save(self, preferenceDialog):
        (x,y) = myLaszloPartyFrame.GetPositionTuple()
        (w,h) = myLaszloPartyFrame.GetSizeTuple()
        self.cfg.WriteInt("APP_X", x)
        self.cfg.WriteInt("APP_Y", y)
        self.cfg.WriteInt("APP_WIDTH", w)
        self.cfg.WriteInt("APP_HEIGHT", h)        
        self.cfg.Write("LZX_LPS_TOOLS_BASEPATH", preferenceDialog.t1.GetValue())
        self.cfg.Write("LZX_LPS_COMPONENTS_BASEPATH", preferenceDialog.t2.GetValue())
        
        
       
class PreferenceDialog(wx.Frame):
    def __init__(self, parent, id=-1, title="Hello"):
        self.parent = parent
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(600, 400))

        wx.StaticText(self, -1, 'Width:', (10, 20))
        wx.StaticText(self, -1, 'Height:', (10, 50))
        self.sc1 = wx.SpinCtrl(self, -1, str(myLaszloPartyPreferences.APP_WIDTH), (80, 15), (60, -1), min=200, max=1000)
        self.sc2 = wx.SpinCtrl(self, -1, str(myLaszloPartyPreferences.APP_HEIGHT), (80, 45), (60, -1), min=200, max=1000)
        
        wx.StaticText(self, -1, 'Tools:', (10, 80))
        wx.StaticText(self, -1, 'Components:', (10, 110))
        self.t1 = wx.TextCtrl(self, -1, myLaszloPartyPreferences.LZX_LPS_TOOLS_BASEPATH, pos=(80,80), size=(400, -1))
        self.t2 = wx.TextCtrl(self, -1, myLaszloPartyPreferences.LZX_LPS_COMPONENTS_BASEPATH, pos=(80,110),size=(400, -1))
        wx.Button(self, 1, 'Save', (10, 140))
        wx.Button(self, 2, '...', (500, 80))
        wx.Button(self, 3, '...', (500, 110))

        self.Bind(wx.EVT_BUTTON, self.OnSave, id=1)
        self.Bind(wx.EVT_BUTTON, self.OnToolsSave, id=2)
        self.Bind(wx.EVT_BUTTON, self.OnComponentsSave, id=3)
        self.statusbar = self.CreateStatusBar()
        self.Centre()

    def OnSave(self, event):
        myLaszloPartyPreferences.save(self)
        self.statusbar.SetStatusText('Configuration saved, %s ' % wx.Now())
    
    def OnToolsSave(self, event):
        dialog = wx.DirDialog(None, "Choose a directory:",style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
        if dialog.ShowModal() == wx.ID_OK:
            dialogPath = dialog.GetPath()
        dialog.Destroy()
        self.t1.SetValue(dialogPath)

    def OnComponentsSave(self, event):
        dialog = wx.DirDialog(None, "Choose a directory:",style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
        if dialog.ShowModal() == wx.ID_OK:
            dialogPath = dialog.GetPath()
        dialog.Destroy()
        self.t2.SetValue(dialogPath)

class MyLazyProjectFrame(wx.Panel):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Panel.__init__(self, *args, **kwds)
        self.tree = wx.GenericDirCtrl(defaultFilter=0, dir='.', filter='',
                        name='dirPicker', parent=self, pos=wx.Point(0, 80), size=wx.Size(300, -1),
                        style= wx.DIRCTRL_3D_INTERNAL ) #| wx.DIRCTRL_DIR_ONLY)

        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.tree, 1, wx.EXPAND, 0)
        self.SetAutoLayout(True)
        self.SetSizer(sizer)
        sizer.Fit(self)
        sizer.SetSizeHints(self)
        self.Layout()
        self.tree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnContextMenu)

    def OnContextMenu(self, event):
        # only do this part the first time so the events are only bound once
        #
        # Yet another anternate way to do IDs. Some prefer them up top to
        # avoid clutter, some prefer them close to the object of interest
        # for clarity. 
        self.path = self.tree.GetPath()
        if not hasattr(self, "popupID1"):
            self.popupID1 = wx.NewId()
            self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1)

        # make a menu
        menu = wx.Menu()
        # Show how to put an icon in the menu
        item = wx.MenuItem(menu, self.popupID1,"open LZX file")
        menu.AppendItem(item)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(menu)
        menu.Destroy()


    def OnPopupOne(self, event):
        myLaszloPartyFrame.LoadAndOpenFile(self.path)
        

    
class MyLaszloPartyFrame(wx.Frame):
    startValue = 4711
    def __init__(self, parent, id=-1, title='wx.aui Test', pos=(0,0), size=(800,600),
                 style=wx.DEFAULT_FRAME_STYLE):
        wx.Frame.__init__(self, parent, id, title, pos, size, style)
        self.parent = parent
        ## widgets
        self.statusbar = MyStatusBar(self)
        self.SetStatusBar(self.statusbar)
        self.SetStatusText("Application launched")
        self.menubar = MyMenuBar(self)
        self.notebookPanel = MyNotebookPanel(self)
        self.toolbar = MyToolBar(self)
        #self.projectSelector = wx.TextCtrl(self, -1, 'Pane 1 - sample text', wx.DefaultPosition, wx.Size(200,150), wx.NO_BORDER | wx.TE_MULTILINE)
        self.keywords = LaszloKeywords(self)
        self.outputPanel = MyOutputList(self)
        self.projectSelector = MyLazyProjectFrame(self)
        #wx.TextCtrl(self, -1, '', wx.DefaultPosition, wx.Size(200,150), wx.NO_BORDER | wx.TE_MULTILINE)
        
        ## Events
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        ## add the panes to the manager
        self.auiWindowsManager = MyAUIManager(self)

    def OnClose(self, event):
        self.auiWindowsManager.UnInit()
        self.Destroy()

    def OnNewPage(self, event):
        self.notebookPanel.addNewPage()
        self.auiWindowsManager.Update()

    def OnPrettyPrint(self,event):
        self.notebookPanel.doPrettyPrint()
        self.auiWindowsManager.Update()
    
    def OnUndo(self,event):
        self.notebookPanel.doUndo()
        self.auiWindowsManager.Update()

    def OnRedo(self,event):
        self.notebookPanel.doRedo()
        self.auiWindowsManager.Update()
    
    def OnToggleEOL(self,event):
        self.notebookPanel.toggleEOL()
        self.auiWindowsManager.Update()
    
    def OnCheckSyntax(self,event):
        self.notebookPanel.checkSyntax()
        self.auiWindowsManager.Update()
    
    def informUser(self, message):
        self.SetStatusText(message)
        self.AddTextToOutputPanel(self.outputPanel.normalIcon(), message)

    def warnUser(self, message):
        self.SetStatusText(message)
        self.AddTextToOutputPanel(self.outputPanel.warningIcon(), message)
                
    def alarmUser(self, message):
        self.SetStatusText(message)
        self.AddTextToOutputPanel(self.outputPanel.alarmIcon(), message)
        
    def SetStatusText(self, newValue):
        self.statusbar.SetStatusText(newValue,1)

    def AddTextToOutputPanel(self, iconindex, newValue):
        textToBeShown = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + "    " + newValue
        self.outputPanel.InsertImageStringItem(0, textToBeShown, iconindex)
    
    def OnFileOpen(self, event):
        filename = wx.LoadFileSelector("load file", ".lzx", "*.lzx" ,parent=self)
        self.LoadAndOpenFile(filename)

    def LoadAndOpenFile(self, filename):
        if filename[-4:] != ".lzx" or filename == u"":
            wx.MessageBox("only LZX files can be loaded into the editor")
        else:
            f = open(filename)
            fileContent = f.read()
            f.close()
            (dirName, fileName) = os.path.split(filename)
            self.notebookPanel.addNewPage(text=fileContent, label=fileName)
        
    def OnFileSave(self, event):
        self.notebookPanel.savePage()
    
    def OnAbout(self,event):
        dlg = AboutDialog(self)
        dlg.ShowModal()
        dlg.Destroy()
        
    def OnPreferences(self, event):
        prf = PreferenceDialog(self)
        prf.Show(True)
        #self.parent.SetTopWindow(prf)


class LaszloKeywords:
    def __init__(self, frame):
        self._frame = frame
        self.loadLZXKeywords()
        self._lzx_componentClasses = self.walkLibraries(myLaszloPartyPreferences.LZX_LPS_COMPONENTS_BASEPATH)
    
    def loadLZXKeywords(self):
        try:        
            tree = etree.parse(myLaszloPartyPreferences.LZX_LPS_TOOLS_BASEPATH + myLaszloPartyPreferences.LZX_LPS_TOOLS_GRAMMARFILE)
            self._lzx_grammar_tree = tree.getroot()
            self._frame.SetStatusText("lzx grammar imported")
        except:
            self._frame.SetStatusText("error reading grammar file: '"+myLaszloPartyPreferences.LZX_LPS_TOOLS_GRAMMARFILE+"' not found")
    
    def getLZXKeywordList(self):
        list = []
        xpath_list = self._lzx_grammar_tree.xpath('/grammar/define/element')
        assert xpath_list != []
        for a in xpath_list:
            list.append(str(a.attrib['name']).upper())
        return list
    
    def getClassList(self):
        return self._lzx_componentClasses
    
    def walkLibraries(self, rootpath):
        list = []
        for filename in self.walkCallback(rootpath):
            if filename[-4:] == ".lzx":
                for a in self.getIncludedClasses(filename):
                    list.append(a)
        return list
        
    def walkCallback(self, startdirectory):
        stack = [startdirectory]
        files = []
        while stack:
            directory = stack.pop()
            for file in os.listdir(directory):
                fullname = os.path.join(directory, file)
                files.append(fullname)
                if os.path.isdir(fullname) and not os.path.islink(fullname):
                    stack.append(fullname)
        return files

        
    def getIncludedClasses(self, filename):
        list = []
        try:
            tree = etree.parse(filename)
    #        print "-"*80
    #        print filename
            for foundClass in tree.xpath("/library/class"):
                #print " -"+"-"*20
                list.append( foundClass.get('name') )
    #            print     "  C-- "+foundClass.get('name').upper()
    #            for attrs in foundClass.keys():
    #                print "   P-- "+str(attrs) + " ("+ foundClass.get(attrs)+")"
    #
    #            for att in foundClass.xpath('attribute'):
    #                print "    A-- "+str( att.get('name') ) 
    #                for attrs in att.keys():
    #                    print "       P-- "+str(attrs) + " ("+ att.get(attrs)+")"
    #            for meth in foundClass.xpath('method'):
    #                print "    M-- "+str( meth.get('name') ) 
    #                for attrs in meth.keys():
    #                    print "       P-- "+str(attrs) + " ("+ meth.get(attrs)+")"
        except:
            #print "error reading: "+filename
            return []
        return list
    

class LaszloApp(wx.App):
    def OnInit(self):
        wx.SplashScreen(wx.Image(ICON_SPLASH_SCREEN, wx.BITMAP_TYPE_PNG).ConvertToBitmap(),
                        wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT, 1000, None, -1)
        wx.Yield()
        return True


try:        
    app = LaszloApp()
    myLaszloPartyPreferences = PreferenceData()
    myLaszloPartyFrame = MyLaszloPartyFrame(None, 
                                            pos=(myLaszloPartyPreferences.APP_X, myLaszloPartyPreferences.APP_Y), 
                                            size=(myLaszloPartyPreferences.APP_WIDTH, myLaszloPartyPreferences.APP_HEIGHT)
                                            )
    myLaszloPartyFrame.Show()
    provider = wx.CreateFileTipProvider("tips.txt",1)
    wx.ShowTip(myLaszloPartyFrame, provider, True)
    app.MainLoop()
except Exception, err:
    app = wx.App()
    frame = wx.Frame(None, -1, "Error starting LaszloParty", wx.DefaultPosition, wx.Size(620, 150))
    frame.SetBackgroundColour(wx.WHITE)
    frame.message = wx.StaticText(frame, -1, str(err), (5, 30))
    frame.message2 = wx.StaticText(frame, -1, str(sys.exc_info()[0]), (5,10))
    frame.Center()
    frame.Show()
    app.MainLoop()